#!/usr/bin/perl

use strict;
use warnings;

use Cwd "abs_path";
use File::Basename;
use FindBin;

my $p5_metaconfig_base = abs_path "$FindBin::Bin/../";

chdir "$p5_metaconfig_base/perl" or
    die "Cannot use $p5_metaconfig_base/perl to find config.sh\n";
my @config = sort { -M $a <=> -M $b }
	     grep { -s }
	     qw( config.sh uconfig.sh Porting/config.sh );
@config or die "Build (and test) perl before generating the Glossary\n";
# Get the list of config.sh symbols.  Be sure this is up to date!
# (I run the Porting/mksample script first to be sure.)
$config[0] eq "config.sh" or warn "Using $config[0] instead of config.sh - Did you build?\n";
my $wanted = abs_path $config[0];

chdir "$p5_metaconfig_base/U" or
    die "Cannot use $p5_metaconfig_base/U to find the units\n";
my @perl_units = map { abs_path $_ } (sort glob "*/*.U"), sort glob "../dist/U/*.U";

open my $wfh, "<", $wanted or die "$0: open $wanted: $!\n";
my @WANTED = map  { $_->[0] }
	     sort { $a->[1] cmp $b->[1] }
	     map  { [ $_, lc $_ ] }
	     <$wfh>;
close $wfh;

print <<'EOM';

!!!!!!!   DO NOT EDIT THIS FILE   !!!!!!!
This file is built by metaconfig.

This file contains a description of all the shell variables whose value is
determined by the Configure script.  Variables intended for use in C
programs (e.g. I_UNISTD) are already described in config_h.SH.  [`configpm'
generates pod documentation for Config.pm from this file--please try to keep
the formatting regular.]

EOM

my ($Loc, %expl, %file, %predef);
foreach my $file (@perl_units) {
    open my $fh, "<", $file or die "$0: open $file: $!";
    my $base = basename ($file);
    $Loc = $file, next if $base eq "Loc.U" and not defined $Loc;
    my @var;
    while (<$fh>) {
	if (m/^\?S:\w+[ \t:]/ .. m/^\?S:\.$/) {
	    s/[ \t]+$//;
	    if (m/^\?S:.$/) {
		my ($var) = ((shift @var) =~ /^(\w+)/);
		unless (exists $expl{$var}) {
		    $expl{$var} = [ @var, "\n" ];
		    $file{$var} = $base;
		    }
		@var = ();
		}
	    else {
		s/^\?S://;		# Remove leading ?S: markers.
		s/^\s+(?=.)/\t/;	# Ensure all lines begin with tabs.
		push @var, $_;
		}
	    }
	}
    close $fh or die "$0: close $file: $!";
    }

defined $Loc or die "$0: Couldn't locate Loc.U: $!";

open my $fh, "<", $Loc or die "$0: open $Loc: $!";
while (<$fh>) {
    m/^\?(\w+):\1$/ and ($expl{$1}, $file{$1}) = (1, "Loc.U");
    }
close $fh or die "$0: close $Loc: $!";

{   local $/ = "\n\n";
    for (<DATA>) {
	m/^(\w+)/;
	$predef{$1} = $_;
	}
    }

for (@WANTED) {
    chomp;
    m/^#/ and next;	# Skip comments
    m/^:/ and next;	# Skip comments
    m/^$/ and next;	# Skip empty sections
    my ($var, $val) = split /=/, $_, 2;

    if (exists $expl{$var}) {
	if ($file{$var} eq "Loc.U") {
	    print "$var (Loc.U):\n";
	    if ($val eq "''") {
		# If we didn't have d_portable, this info might be
		# useful, but it still won't help with non-standard
		# stuff if perl is built on one system but installed
		# on others (this is common with Linux distributions,
		# for example).
		print <<EOE;
	This variable is defined but not used by Configure.
	The value is the empty string and is not useful.

EOE
		}
	    else {
		print <<EOE;
	This variable is used internally by Configure to determine the
	full pathname (if any) of the $var program.  After Configure runs,
	the value is reset to a plain "$var" and is not useful.

EOE
		}
	    }
	else {
	    print "$var ($file{$var}):\n";
	    print @{$expl{$var}};
	    }
	next;
	}

    # Handle special variables from Oldsyms.U.  Since these start
    # with capital letters, metalint considers them to be "special
    # unit" symbols.  It's easier to define them here than to try
    # to fool metalint any further.   --AD  22 Oct 1999
    # Similarly, handle the config_arg* variables from Options.U.
    # -- AD 8 Dec 2009
    if (exists $predef{$var}) {
	print  $predef{$var};
	next;
	}

    $var =~ /^(Author|Date|Header|Id|Locker|Log|Mcc|RCSfile|Revision|Source|State)$|_cflags$|^config_arg/
	or warn "$0: couldn't find $var\n"
    }
__END__
PERL_REVISION (Oldsyms.U):
	In a Perl version number such as 5.6.2, this is the 5.
	This value is manually set in patchlevel.h

PERL_VERSION (Oldsyms.U):
	In a Perl version number such as 5.6.2, this is the 6.
	This value is manually set in patchlevel.h

PERL_SUBVERSION (Oldsyms.U):
	In a Perl version number such as 5.6.2, this is the 2.
	Values greater than 50 represent potentially unstable
	development subversions.
	This value is manually set in patchlevel.h

PERL_APIVERSION (Oldsyms.U):
	This value is manually set in patchlevel.h and is used
	to set the Configure apiversion variable.

CONFIGDOTSH (Oldsyms.U):
	This is set to 'true' in config.sh so that a shell script
	sourcing config.sh can tell if it has been sourced already.

PERL_CONFIG_SH (Oldsyms.U):
	This is set to 'true' in config.sh so that a shell script
	sourcing config.sh can tell if it has been sourced already.

PERL_API_REVISION (patchlevel.h):
	This number describes the earliest compatible PERL_REVISION of
	Perl ("compatibility" here being defined as sufficient binary/API
	compatibility to run XS code built with the older version).
	Normally this does not change across maintenance releases.
	Please read the comment in patchlevel.h.

PERL_API_VERSION (patchlevel.h):
	This number describes the earliest compatible PERL_VERSION of
	Perl ("compatibility" here being defined as sufficient binary/API
	compatibility to run XS code built with the older version).
	Normally this does not change across maintenance releases.
	Please read the comment in patchlevel.h.

PERL_API_SUBVERSION (patchlevel.h):
	This number describes the earliest compatible PERL_SUBVERSION of
	Perl ("compatibility" here being defined as sufficient binary/API
	compatibility to run XS code built with the older version).
	Normally this does not change across maintenance releases.
	Please read the comment in patchlevel.h.

PERL_PATCHLEVEL (Oldsyms.U):
	This symbol reflects the patchlevel, if available. Will usually
	come from the .patch file, which is available when the perl
	source tree was fetched with rsync.

config_args (Options.U):
	This variable contains a single string giving the command-line
	arguments passed to Configure.	Spaces within arguments,
	quotes, and escaped characters are not correctly preserved.
	To reconstruct the command line, you must assemble the individual
	command line pieces, given in config_arg[0-9]*.

config_arg0 (Options.U):
	This variable contains the string used to invoke the Configure
	command, as reported by the shell in the $0 variable.

config_argc (Options.U):
	This variable contains the number of command-line arguments
	passed to Configure, as reported by the shell in the $# variable.
	The individual arguments are stored as variables config_arg1,
	config_arg2, etc.

